﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Text;
using System.Text.RegularExpressions;

using Sofire.Data;
using Sofire.Dynamic;
using Sofire.Dynamic.Factories;
using System.Collections.ObjectModel;
using System.Reflection;

namespace System.Data
{
    /// <summary>
    /// 数据的扩展方法集合。
    /// </summary>
    public static class DataExts
    {
        /// <summary>
        /// 生成一个描述查询操作结果的字符串。
        /// </summary>
        /// <param name="result">查询操作的结果。</param>
        /// <param name="type">查询的类型。</param>
        /// <returns>返回一个描述查询操作结果的字符串。</returns>
        public static string BuilderResultLog(this IQueryResult result, ExecuteType type)
        {
            if(result == null) return string.Empty;
            if(result.Command == null) return "\r\n【查询语句】：\r\n\r\n\t出于性能考虑，拒绝解析多个查询语句。";
            string commandText = result.Command.CommandText;
            StringBuilder builder = new StringBuilder("\r\n【查询语句】：\r\n\r\n\t");
            builder.Append(commandText);
            
            string paras = string.Empty;
            bool hasParameters = result.Command.Parameters.Count > 0;
            bool isProcedure = result.Command.CommandType == CommandType.StoredProcedure;
            if(hasParameters)
            {
                string name, value;
                foreach(DbParameter item in result.Command.Parameters)
                {
                    name = item.ParameterName;
                    if(result.QueryEngine is OracleQuery) name = ":" + name;
                    if(item.Value == null || Convert.IsDBNull(item.Value))
                    {
                        paras += "\r\n\t" + name + " IS NULL ";
                        continue;
                    }

                    value = "'" + item.Value.ToString() + "'";

                    paras += "\r\n\t" + name + " = " + value;
                    if(!isProcedure)
                    {
                        commandText = Regex.Replace(commandText, name + @"(?![\w])", value + " /* " + name + " */ ", RegexOptions.IgnoreCase);
                    }
                }
            }

            if(!isProcedure && hasParameters)
            {
                builder.Append("\r\n\r\n【查询参数】：");
                builder.Append(paras);
            }

            builder.Append("\r\n\r\n【命令分析】：\r\n\r\n\t");

            if(isProcedure)
            {
                if(paras.Length > 0)
                {
                    paras = paras.Replace("\t", "\t\t,");
                    var i = paras.IndexOf(',');
                    if(i > -1) paras = paras.Remove(i, 1);
                }
                builder.Append("EXEC ");
                builder.Append(commandText);
                builder.Append(paras);
            }
            else
            {
                builder.Append(commandText);
            }

            if(result.IsSucceed)
            {
                builder.Append("\r\n\r\n【操作结果】：\r\n\r\n\t");
                switch(type)
                {
                    case ExecuteType.MultiNoQuery:
                    case ExecuteType.Transaction:
                    case ExecuteType.NoQuery:
                        {
                            builder.Append(result.Value);
                            builder.Append(" 行受影响");
                            break;
                        }
                    case ExecuteType.DataSet:
                        {
                            var tables = (result as DataSetResult<DataSet>).Value.Tables;

                            builder.Append("找到 ");
                            builder.Append(tables.Count);
                            builder.Append(" 张表 ");
                            int totalCount = 0;
                            foreach(DataTable table in tables)
                            {
                                totalCount += table.Rows.Count;
                            }
                            builder.Append(totalCount);
                            builder.Append(" 条记录");
                            break;
                        }
                    case ExecuteType.Table:
                        {
                            var table = (result as TableResult).Value;
                            builder.Append("找到 ");
                            builder.Append(table.Rows.Count);
                            builder.Append(" 条记录");
                            break;
                        }
                    case ExecuteType.Scalar:
                        {
                            var value = result.Value;
                            builder.Append(value == null ? "返回一个 null 值" : value.ToString());
                            break;
                        }
                    case ExecuteType.Reader:
                    case ExecuteType.Unknow:
                        {
                            builder.Append("数据读取器没有返回值");
                            break;
                        }
                    default:
                        break;
                }
            }
            else if(result.IsIgnored)
            {
                builder.Append("\r\n\r\n【结果已被忽略】：\r\n\r\n\t");
                builder.Append(result.Exception);
            }
            else
            {
                builder.Append("\r\n\r\n【操作异常】：\r\n\r\n\t");
                if(type == ExecuteType.MultiNoQuery || type == ExecuteType.Transaction)
                {
                    builder.Append("错误发生在索引 [");
                    builder.Append((result as MultiNonQueryResult).ErrorIndex);
                    builder.Append("] 的命令。");
                }
                builder.Append(result.Exception);
            }
            builder.Append("\r\n\r\n");
            return builder.ToString();
        }

        /// <summary>
        /// 指定实体类型，动态创建当前数据表的新实体集合。
        /// </summary>
        /// <typeparam name="TEntity">映射的实体类型。</typeparam>
        /// <param name="table">映射的数据表。</param>
        /// <returns>返回一个成功初始化的实例集合或 null 值。</returns>
        public static DynamicEntityCollection<TEntity> CreateEntities<TEntity>(this DataTable table)
            where TEntity : new()
        {
            if(table == null)
                return null;
            return new DynamicEntityCollection<TEntity>(table);
        }

        /// <summary>
        /// 指定实体类型，动态创建当前数据表的新实体只读集合。
        /// </summary>
        /// <typeparam name="TEntities">映射的实体集合类型。</typeparam>
        /// <typeparam name="TEntity">映射的实体类型。</typeparam>
        /// <param name="table">映射的数据表。</param>
        /// <returns>返回一个成功初始化的实例集合或 null 值。</returns>
        public static TEntities CreateReadonlyEntities<TEntities, TEntity>(this DataTable table)
            where TEntities : class, ICollection<TEntity>, new()
            where TEntity : new()
        {
            if(table == null)
                return null;
            var entityType = typeof(TEntity);
            TEntities entities = new TEntities();

            var mapping = EntityMapper.Create(typeof(TEntity));
            foreach(DataRow row in table.Rows)
            {
                TEntity entity = new TEntity();
                mapping.FillEntity(row, entity);
                entities.Add(entity);
            }

            return entities;
        }

        /// <summary>
        /// 指定实体类型，动态创建当前数据表的新实体。
        /// </summary>
        /// <typeparam name="TEntity">映射的实体类型。</typeparam>
        /// <param name="table">映射的数据表。</param>
        /// <returns>返回一个成功初始化的实例或 null 值。</returns>
        public static TEntity CreateEntity<TEntity>(this DataTable table)
            where TEntity : new()
        {
            if(table == null || table.Rows.Count == 0)
                return default(TEntity);
            return DataExts.CreateEntity<TEntity>(table.Rows[0]);
        }

        /// <summary>
        /// 指定实体类型，动态创建当前数据行的新实体。
        /// </summary>
        /// <typeparam name="TEntity">映射的实体类型。</typeparam>
        /// <param name="row">映射的数据行。</param>
        /// <returns>返回一个成功初始化的实例或 null 值。</returns>
        public static TEntity CreateEntity<TEntity>(this DataRow row)
            where TEntity : new()
        {
            return CreateEntity<TEntity>(row, EntityMapper.Create(typeof(TEntity)));
        }

        /// <summary>
        /// 指定实体类型，动态创建当前数据行的新实体。
        /// </summary>
        /// <typeparam name="TEntity">映射的实体类型。</typeparam>
        /// <param name="row">映射的数据行。</param>
        /// <param name="mapping">设置器映射。</param>
        /// <returns>返回一个成功初始化的实例或 null 值。</returns>
        public static TEntity CreateEntity<TEntity>(this DataRow row, IEntityMapper mapping)
           where TEntity : new()
        {
            if(row == null || mapping == null) return default(TEntity);

            TEntity entity = new TEntity();

            mapping.FillEntity(row, entity);

            return entity;
        }

        /// <summary>
        /// 将基于 <see cref="Sofire.Data.ExecuteCommandBase"/> 的派生类集合转换为基类集合。
        /// </summary>
        /// <typeparam name="T"><see cref="Sofire.Data.ExecuteCommandBase"/> 的派生类。</typeparam>
        /// <param name="commands">命令的集合。</param>
        /// <returns>返回一个新的基类集合。</returns>
        public static List<ExecuteCommandBase> ToCommandList<T>(this IList<T> commands)
            where T : ExecuteCommandBase
        {
            if(commands == null) return null;
            List<ExecuteCommandBase> commandBases = new List<ExecuteCommandBase>(commands.Count);
            foreach(var c in commands)
            {
                commandBases.Add(c);
            }
            return commandBases;
        }

        /// <summary>
        /// 当数据源的状态为打开时，尝试关闭连接。该方法可以避免异常的抛出。
        /// </summary>
        public static void TryClose(this DbConnection conn)
        {
            if(conn != null && conn.State != ConnectionState.Closed)
            {
                try
                {
                    conn.Close();
                }
                catch(Exception) { }
            }
        }
    }
}